import datetime
import random
import sys
import time

import cv2
import numpy as np

from libs.action import WebDriverAction
from libs.game import Game
from libs.image import ImageTool
from libs.log import Log
from libs.movement import Movement, KeyCode
from libs.task_helper import TaskHelper
from libs.trade_helper import TradeHelper
from libs.window import AdsWindow


def select_image(try_x, try_y, previous_guess, current_gusss):
    offset_y = -100
    offset_xs = [-135, 0, 135, 270]
    for index in range(4):
        prev = -1
        current = -1
        if previous_guess[index]:
            prev = images.index(previous_guess[index])
        if current_gusss[index]:
            current = images.index(current_gusss[index])
        if current >= prev:
            click_times = current - prev
        else:
            click_times = len(images) + current - prev
        offset_x = offset_xs[index]
        action.move_by_offset(try_x + offset_x, try_y + offset_y)
        for _ in range(click_times):
            action.click()
            time.sleep(random.randint(2, 5)/10)


# 猜测逻辑
def solve_game(try_x, try_y):
    possible_images = set(images)
    excluded_images = []
    excluded_positions = [set() for _ in range(4)]  # 每个位置排除的图片
    correct_positions = [None] * 4  # 如果图片和位置正确，锁定
    misplaced_candidates = {}  # 记录 xo 的图片及其候选位置
    previous_guess = [None] * 4  # 上一次猜测的序列
    current_guess = [None] * 4  # 当前猜测的序列

    # 首次尝试使用4个不同的图片以测试更多图片
    unused_images = list(possible_images)
    attempt = 0
    for row in range(5):  # 最多五次尝试
        if attempt >= 5:
            break
        if attempt <= 3 and len([x for x in correct_positions if x is not None]) == 3:
            pass
        else:
            # 如果位置已经正确，直接填充
            for i in range(4):
                if correct_positions[i] is not None:
                    current_guess[i] = correct_positions[i]

        attempt += 1
        # 处理 "xo" 的图片：尝试移动它们到其他未排除的位置
        for candidate in misplaced_candidates:
            invalid_positions = misplaced_candidates.get(candidate, [])
            for i in range(4):
                if current_guess[i] is not None:
                    continue
                if i in invalid_positions:
                    continue
                if candidate in current_guess:
                    continue
                current_guess[i] = candidate
                break

        # 使用unused_images填充
        for i in range(4):
            if current_guess[i] is None:
                for img in unused_images:
                    if img in excluded_positions[i]:
                        continue
                    if img in excluded_images:
                        continue
                    current_guess[i] = img
                    unused_images.remove(img)
                    break

        # 使用 possible_images 填充
        for i in range(4):
            if current_guess[i] is None:
                for img in possible_images:
                    if img in excluded_positions[i]:
                        continue
                    if img in excluded_images:
                        continue
                    current_guess[i] = img
                    if img in unused_images:
                        unused_images.remove(img)
                    break

        print(f"[{attempt}]guess:", current_guess)
        select_image(try_x, try_y, previous_guess, current_guess)
        action.click_by_offset(try_x + 70, try_y + 25)
        time.sleep(1)
        feedback = get_feedback(try_x, try_y, row)
        print(f"[{attempt}]feedback:", feedback)

        # 如果完全正确，直接返回
        if all(f == "oo" for f in feedback):
            print("Correct sequence found:", current_guess)
            return current_guess

        # 更新状态
        for i, f in enumerate(feedback):
            if f == "oo":
                correct_positions[i] = current_guess[i]
                excluded_positions[i] = set()  # 位置正确，清空排除列表
            elif f == "xo":
                excluded_positions[i].add(current_guess[i])  # 此图片不能在当前的位置
                invalid_positions = misplaced_candidates.get(current_guess[i], [])
                invalid_positions.append(i)
                misplaced_candidates[current_guess[i]] = invalid_positions
            elif f == "xx":
                excluded_images.append(current_guess[i])

        # print('exclude_images', excluded_images)
        # print('misplaced_candidates', misplaced_candidates)
        # 保留错误或未填满的图片到未使用池中
        unused_images.extend(img for img in current_guess if img not in correct_positions and img not in unused_images)

        # 清空当前猜测准备下一次尝试
        previous_guess = current_guess[:]
        current_guess = [None] * 4

    print("Game over, failed to find the correct sequence.")
    return None


def get_feedback(try_x, try_y, row):
    feedback_points = [
        (try_x - 162 + col * 128, try_y - 310 - row * 80)  # 计算每个格子的右下角坐标
        for row in range(5)  # 5 行
        for col in range(4)  # 4 列
    ]
    feedback = []
    for x, y in feedback_points[row * 4:(row + 1) * 4]:
        bg_color = get_pixel_color(x, y)
        if bg_color == (26, 213, 23):  # 绿色
            feedback.append("oo")
        elif bg_color == (240, 255, 63):  # 黄色
            feedback.append("xo")
        else:
            feedback.append("xx")

    return feedback


def get_pixel_color(x, y):
    """
    获取屏幕指定位置 (x, y) 的像素颜色
    :param x: 横坐标
    :param y: 纵坐标
    :return: (R, G, B) 的元组
    """
    # 获取整个屏幕的截图
    screenshot_data = driver.get_screenshot_as_png()
    screenshot = cv2.imdecode(np.frombuffer(screenshot_data, np.uint8), cv2.IMREAD_COLOR)

    # 检查坐标是否在截图范围内
    height, width, _ = screenshot.shape
    if 0 <= y < height and 0 <= x < width:
        # OpenCV 的图像是 BGR 排序，需要转成 RGB
        b, g, r = screenshot[y, x]
        return int(r), int(g), int(b)  # 返回 RGB 值
    else:
        raise ValueError(f"坐标 ({x}, {y}) 超出了截图范围 (宽: {width}, 高: {height})")


if __name__ == "__main__":
    parser = TaskHelper.default_args_parser('Pixmax Guess')
    args = parser.parse_args()
    task_helper = TaskHelper.from_args(args)

    user_id = args.user_id
    log = Log(user_id)

    try:
        driver = AdsWindow(user_id).open(False)
        game = Game(driver, user_id)
        action = WebDriverAction(driver)
        movement = Movement(driver)
        image_tool = ImageTool(driver)
        trade_helper = TradeHelper(driver, user_id)

        # 定义图片集合和验证函数
        images = ["hat", "snowflake", "bear", "tree", "snowman", "flour", "gift", "candy", "cloth"]

        game.enter_game()

        cookie_name = 'Cookie Credit'
        cookie_index, cookie_qty = game.get_backpack_index_and_qty(cookie_name)
        log.debug(f'start_cookie_qty={cookie_qty}')
        if cookie_qty < 2:
            task_helper.task_success()
            sys.exit()

        door_loc = None
        for _ in range(3):
            door_loc = image_tool.find_target('carnival/carnival_door.png')
            if door_loc:
                break
            action.goto_spec()
            action.goto_terra()
            movement.keep_move_left(1)
            tent_loc = image_tool.find_target('carnival/carnival_tent.png')
            if tent_loc:
                action.move_to('carnival/carnival_tent.png', max_loop=3)
                action.move_by_offset(200, 200)
                time.sleep(0.5)
                tent_loc = image_tool.find_target('carnival/carnival_tent.png')
                tent_x, tent_y = tent_loc
                action.click_by_offset(tent_x, tent_y)
                action.wait_page_loaded()

        if door_loc is None:
            log.debug('enter carnival failed')
            # task_helper.add_task('pixmas_.py', delay_seconds=0, ignore_running=True, priority=9, retry=True)
            sys.exit()

        tree_loc = None
        for _ in range(3):
            tree_loc = image_tool.find_target('carnival/carnival_tree.png')
            if tree_loc:
                break
            movement.keep_move_up(5)

        movement.keep_move_left(0.5)
        movement.keep_move_up(5)

        movement.keep_move_right(0.5)
        movement.keep_move_up(3)
        movement.keep_move_down(0.3)
        movement.keep_move_right(1.5)
        movement.keep_move_up(3)
        movement.keep_move_down(0.3)
        movement.keep_move_right(2)
        movement.keep_move_up(0.5)

        movement.send_key_down(KeyCode.RIGHT)
        ctc_image = 'carnival/carnival_crack_the_code.png'
        for _ in range(15):
            ctc_loc = image_tool.find_target(ctc_image)
            if ctc_loc is not None:
                break
            time.sleep(0.5)

        movement.send_key_up(KeyCode.RIGHT)
        action.move_to(ctc_image, delta_x=100, delta_y=50)
        action.wait_page_loaded()

        movement.keep_move_up(3)
        movement.keep_move_right(0.5)
        movement.keep_move_up(1.5)
        movement.keep_move_right(4)
        movement.keep_move_up(2)
        time.sleep(1)

        for _ in range(30):
            game.enter_game()
            start_loc = image_tool.find_target('carnival/carnival_start.png')
            start_x, start_y = start_loc
            start_x += 85
            start_y += 85
            for _ in range(120):
                if action.hover_bubble_text_has(start_x, start_y, 'FINISH GAME'):
                    break
                if action.hover_bubble_text_has(start_x, start_y, 'Play again in'):
                    break
                if action.hover_bubble_text_has(start_x, start_y, 'to Start'):
                    game.use_backpack_item(cookie_index)
                    action.click()
                    action.click()
                    action.escape()
                    action.escape()
                    continue
            start = datetime.datetime.now()
            movement.keep_move_left(3)
            time.sleep(1)
            try_code_loc = image_tool.find_target('carnival/carnival_try_code.png')
            try_x, try_y = try_code_loc

            solve_game(try_x, try_y)

            movement.keep_move_left(1)
            time.sleep(1)
            prize_loc = image_tool.find_target('carnival/carnival_prize.png')
            prize_x, prize_y = prize_loc
            action.click_by_offset(prize_x, prize_y)
            movement.keep_move_right(5)
            cost = (datetime.datetime.now() - start).seconds
            game.update_backpack([cookie_index])
            cookie_qty = game.get_backpack_qty(cookie_name)
            log.debug(f'cookie_qty={cookie_qty}')
            if cookie_qty < 2:
                break
            if cost < 180:
                log.debug(f'wait {180 - cost} seconds')
                time.sleep(180 - cost)
        task_helper.task_success()
    except Exception as e:
        task_helper.task_fail()
        task_helper.add_task('pixmas_guess.py', delay_seconds=1 * 60, ignore_running=True, priority=9, retry=True)
        raise e
